package com.tanhua.server.service;

import cn.hutool.core.util.PageUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.constant.Constants;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.UserLikeApi;
import com.tanhua.dubbo.api.mongo.VideoApi;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.UserLike;
import com.tanhua.model.mongo.Video;
import com.tanhua.model.vo.CommentVo;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VideoVo;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 小视频业务处理层逻辑
 */
@Slf4j
@Service
public class SmallVideoService {

    @DubboReference
    private VideoApi videoApi;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private FastFileStorageClient client;//文件上传客户端对象 /group1/M00/00/00/wKiIoGG_9YCACIIaAATPmhnHJ_s286.png

    @Autowired
    private FdfsWebServer fdfsWebServer; //获取 http://192.168.136.160:8888/路径


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    /**
     * 视频发布
     *
     * @param videoThumbnail 视频封面文件
     * @param videoFile      视频文件
     * @return
     */
    public void publish(MultipartFile videoThumbnail, MultipartFile videoFile) {
        try {
            Video video = new Video();
            Long userId = UserHolder.getUserId();
            //1.获取当前登录用户id 设置为视频作者id
            video.setUserId(userId);
            //2.视频发布的文字
            video.setText("你喜欢黑丝吗");
            //3.获取视频封面图片地址
            String filename = videoThumbnail.getOriginalFilename();//获取视频封面原始文件名称
            String picUrl = ossTemplate.upload(filename, videoThumbnail.getInputStream());
            video.setPicUrl(picUrl);
            //4.获取视频地址
            String suffix = videoFile.getOriginalFilename().substring(videoFile.getOriginalFilename().lastIndexOf(".") + 1); //.mp4 ==> mp4
            StorePath storePath = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), suffix, null);
            String videoUrl = fdfsWebServer.getWebServerUrl() + storePath.getFullPath();
            video.setVideoUrl(videoUrl);
            //5.调用服务保存视频
            videoApi.add(video);
            log.debug("*****************视频发布成功了*****************");
        } catch (IOException e) {
            log.debug("*****************视频失败了*****************");
            throw new TanHuaException(ErrorResult.error());
        }
    }

    /**
     * 视频列表分页查询（推荐系统视频数据==>视频表分页查询）
     * vids=100个
     * page = 1 pagesize=10
     * page = 12 pagesize=10
     * key=当前用户id_1_10 #page #pagesize
     */
    @Cacheable(value = "videos", key = "T(com.tanhua.server.interceptor.UserHolder).userId + '_' + #page + '_' +#pagesize")
    public PageResult<VideoVo> findPage(Long page, Long pagesize) {
        //1根据key查询redis中Vids是否存在
        String key = Constants.VIDEOS_RECOMMEND + UserHolder.getUserId();
        String vids = stringRedisTemplate.opsForValue().get(key);//推荐使用的vids
        Long counts = 0l;//总记录数
        Long redisPage = 0l;//redis总页码
        List<Video> videoList = new ArrayList();
        //2存在 分页查询 调用服务提供者获取推荐视频列表数据
        if (StringUtils.isNotEmpty(vids)) {
            String[] vidsArr = vids.split(",");//得到视频数组 100个vid 分页得到10个id
            long start = (page - 1) * pagesize;//开始哪条开始查询
            counts = Long.valueOf(vidsArr.length);
            redisPage = (long) PageUtil.totalPage(counts.intValue(), pagesize.intValue()); //10页
            if (counts > start) {
                List<Long> listVids = Arrays.stream(vidsArr).skip(start).limit(pagesize).map(v -> Long.valueOf(v)).collect(Collectors.toList());
                videoList = videoApi.findByVids(listVids);
            }
        }
        //3不存在 直接从数据库直接分页查询视频数据
        if (CollectionUtils.isEmpty(videoList)) {
            PageResult<Video> pageResult = videoApi.findPage(page - redisPage, pagesize);
            videoList = pageResult.getItems();
            counts = pageResult.getCounts();
        }
        List<VideoVo> videoVoList = new ArrayList();
        if (!CollectionUtils.isEmpty(videoList)) {
            //4.获取出所有视频作者ids
            List<Long> listUserIds = videoList.stream().map(Video::getUserId).collect(Collectors.toList());
            //5.根据视频作者ids获取视频作者详情
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(listUserIds, null);
            //6.基于视频作者详情  与 视频对象 构造VideVo返回

            for (Video video : videoList) {
                String key1 = "VIDEO_INTERACT_KEY" + video.getId();//固定的写死 理解为表名 MOVEMENTS_INTERACT_动态id
                String hashKey = "VIDEO_INTERACT_KEY" + UserHolder.getUserId();//某个用户对某个动态点赞key MOVEMENT_LIKE_1 MOVEMENT_LOVE_1
                VideoVo videoVo = VideoVo.init(userInfoMap.get(video.getUserId()), video);
                if (stringRedisTemplate.opsForHash().hasKey(key1, hashKey)) {
                    videoVo.setHasLiked(1);
                }
                videoVoList.add(videoVo);
            }
        }
        return new PageResult<>(page, pagesize, counts, videoVoList);
    }

    /**
     * 小视频-点赞
     *
     * @param id
     */
    public Integer like(String id) {
        //1.现在有的参数
        //1.1当前登录用户的id
        Long userId = UserHolder.getUserId();
        Integer count = videoApi.addLike(id);
        //2.将点赞记录写入redis (当查询动态分页数据时候 可以根据redis有当前用户点赞记录返回0或1)
        //方式一（不推荐）
        //String key = "like_"+movementId+"_"+UserHolder.getUserId();
        //stringRedisTemplate.opsForValue().set(key,"xxxx");
        //方式二（推荐）
        String key = "VIDEO_INTERACT_KEY" + id;//固定的写死 理解为表名 MOVEMENTS_INTERACT_动态id
        String hashKey = "VIDEO_INTERACT_KEY" + userId;//某个用户对某个动态点赞key MOVEMENT_LIKE_1 MOVEMENT_LOVE_1
        stringRedisTemplate.opsForHash().put(key, hashKey, "1");

        return count;

    }


    /**
     * 视频-点赞取消
     */
    public Integer dislike(String Id) {
        //1.现在有的参数
        Integer count = videoApi.dislike(Id);
        //方式二（推荐）
        String key = "VIDEO_INTERACT_KEY" + Id;//固定的写死 理解为表名 VIDEO_INTERACT_动态id
        stringRedisTemplate.delete(key);
        return count;

    }

    /**
     * 小视频评论发布
     *
     * @param id
     * @param text
     */
    public void comments(String id, String text) {
        //创建评论表对象
        Comment comment = new Comment();
        comment.setContent(text);
        comment.setPublishId(new ObjectId(id));
        comment.setCommentType(2);
        comment.setUserId(UserHolder.getUserId());
        //根据动态id查询评论人id
        Video video = videoApi.getVideo(id);
        comment.setPublishUserId(comment.getUserId());
      Integer count =  commentApi.addVideo(comment);
    }

    /**
     * 小视频评论列表查询
     */
    public PageResult<CommentVo> videoList(Long page, Long pageSize, String id) {
        //1根据动态id分页查询评论表
        PageResult<Comment> commentPageResult = videoApi.commentsList(page, pageSize, id);
        if (commentPageResult == null || CollectionUtils.isEmpty(commentPageResult.getItems())) {
            return new PageResult<>(0l, 10l, 0l, 1l, null);
        }
        //2根据评论的作者id 批量获取用户信息
        List<Comment> commentList = commentPageResult.getItems();
        List<Long> listUserIds = commentList.stream().map(Comment::getUserId).collect(Collectors.toList());
        Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(listUserIds, null);

        //3基于评论数据和用户信息 构造Vo
        List<CommentVo> commentVoList = new ArrayList<>();
        for (Comment comment : commentList) {
            String key = "VIDEOS_INTERACT_KEY" + comment.getId();//固定的写死 理解为表名 MOVEMENTS_INTERACT_动态id
            String hashKey = "VIDEOS_INTERACT_KEY" + UserHolder.getUserId();
            CommentVo commentVo = CommentVo.init(userInfoMap.get(comment.getUserId()), comment);
            if (stringRedisTemplate.opsForHash().hasKey(key,hashKey)){

                commentVo.setHasLiked(1);
            }
            commentVoList.add(commentVo);
        }
        //4返回分页Vo
        return new PageResult<>(page, pageSize, commentPageResult.getCounts(), commentVoList);
    }

    /**
     * 小视频评论-点赞
     */
    public Integer commentsLike(String id) {
        //1.现在有的参数
        //1.1当前登录用户的id
        Long userId = UserHolder.getUserId();
        Integer count = videoApi.Like(id);
        //2.将点赞记录写入redis (当查询动态分页数据时候 可以根据redis有当前用户点赞记录返回0或1)
        //方式一（不推荐）
        //String key = "like_"+movementId+"_"+UserHolder.getUserId();
        //stringRedisTemplate.opsForValue().set(key,"xxxx");
        //方式二（推荐）
        String key = "VIDEOS_INTERACT_KEY"+id;//固定的写死 理解为表名 MOVEMENTS_INTERACT_动态id
        String hashKey ="VIDEOS_INTERACT_KEY"+userId;//某个用户对某个动态点赞key MOVEMENT_LIKE_1 MOVEMENT_LOVE_1
        stringRedisTemplate.opsForHash().put(key,hashKey,"1");

        return count;
    }

    /**
     * 小视频评论-点赞取消
     */
    public Integer commentsDislike(String id) {
        //1.现在有的参数
        Integer count = videoApi.dislikes(id);
        //方式二（推荐）
        String key = "VIDEOS_INTERACT_KEY"+id;//固定的写死 理解为表名 MOVEMENTS_INTERACT_动态id
        stringRedisTemplate.delete(key);
        return count;
    }

    /**
     * 小视频-添加关注
     * @param uid
     */
    public void addFocus(Long uid,boolean isLike) {
        Long userId = UserHolder.getUserId();
        //1.调用服务保存 喜欢 或 不喜欢 记录
        UserLike userLike = new UserLike();
        userLike.setUserId(userId);//当前登录用户id
        userLike.setLikeUserId(uid);//喜欢或不喜欢的用户id
        userLike.setIsLike(isLike);//是否喜欢 true:喜欢 false:不喜欢
        boolean isFriend = userLikeApi.save(userLike);
        //2.根据喜欢或不喜欢操作Redis记录 （后续例如：首页点击某个推荐用户 需要查询此redis数据）
        String likeKey = Constants.USER_LIKE_KEY + UserHolder.getUserId();//USER_LIKE_SET_10012  1,2,3
        String unlikeKey = Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId();//USER_NOT_LIKE_SET_10012 4,5,6
        if (isLike) {//喜欢 redis set集合
            stringRedisTemplate.opsForSet().add(likeKey, uid.toString());
            stringRedisTemplate.opsForSet().remove(unlikeKey, uid.toString());
        } else {
            stringRedisTemplate.opsForSet().remove(likeKey, uid.toString());
            stringRedisTemplate.opsForSet().add(unlikeKey, uid.toString());
            userLikeApi.delete(uid,userId);
        }
        //3.如果是互相喜欢调用环信云保存好友关系
        if(isFriend){
            //注意：环信后台一定要先添加测试的用户
            huanXinTemplate.addContact(Constants.HX_USER_PREFIX+userId,Constants.HX_USER_PREFIX+uid);
        }
    }


}
